/*
 * @Author: Vorga
 * @LastEditors: Vorga
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <net/if.h>

#include "network.h"

const char* getip_nw(NetWork* nw)
{
    return inet_ntoa(nw->addr.sin_addr);
}

char* getip_local(void)
{
    //最多获取16个IP
    struct ifreq buf[16];
    struct ifconf ifc;
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sfd < 0) return "404";
    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = (caddr_t)buf;
    //获取网络配置
    if (ioctl(sfd, SIOCGIFCONF, (char*)&ifc)) return "404";
    //计算请求的数量
    int intr = ifc.ifc_len / sizeof(struct ifreq);
    //尽可能的获取IP
    while (intr-- > 0 && ioctl(sfd, SIOCGIFADDR, (char*)&buf[intr]));
    close(sfd);
    //把获取到的地址返回
    //这里返回第一个,也就是内网的IP
    return inet_ntoa(((struct sockaddr_in*)(&buf[intr].ifr_addr))->sin_addr);
}

NetWork* open_nw(NetType type, uint16_t port, const char* ip, NetRole role)
{
    NetWork* nw = malloc(sizeof(NetWork));
    nw->sockfd = socket(AF_INET, type, 0);
    if (0 > nw->sockfd)
    {
        free(nw);
        return NULL;
    }
    // 计算地址结构体的字节数
    nw->addrlen = sizeof(nw->addr);

    // 初始化地址结构体
    bzero(&nw->addr, nw->addrlen);
    nw->addr.sin_family = AF_INET;
    nw->addr.sin_port = htons(port);
    nw->addr.sin_addr.s_addr = inet_addr(ip);

    nw->type = type;
    nw->role = role;

    if (Server == role)
    {
        //bind 
        if (bind(nw->sockfd, (SAP)&nw->addr, nw->addrlen))
        {
            free(nw);
            return NULL;
        }
        // ? listen
        if (TCP == nw->type && listen(nw->sockfd, 16))
        {
            free(nw);
            return NULL;
        }
    }
    else if (TCP == type)
    {
        if (connect(nw->sockfd, (SAP)&nw->addr, nw->addrlen))
        {
            free(nw);
            return NULL;
        }
    }
    return nw;
}

NetWork* accept_nw(NetWork* nw)
{
    if (Server != nw->role || TCP != nw->type) return NULL;
    NetWork* cnw = malloc(sizeof(NetWork));
    cnw->addrlen = sizeof(cnw->addr);
    cnw->sockfd = accept(nw->sockfd, (SAP)&cnw->addr, &cnw->addrlen);
    if (0 > cnw->sockfd)
    {
        free(cnw);
        return NULL;
    }

    cnw->type = TCP;
    cnw->role = Client;

    return cnw;
}

ssize_t send_nw(NetWork* nw, void* buf, size_t len)
{
    if (SOCK_STREAM == nw->type) return send(nw->sockfd, buf, len, 0);
    if (SOCK_DGRAM == nw->type) return sendto(nw->sockfd, buf, len, 0, (SAP)&nw->addr, nw->addrlen);
    return 0;
}

ssize_t recv_nw(NetWork* nw, void* buf, size_t len)
{
    if (SOCK_STREAM == nw->type) return recv(nw->sockfd, buf, len, 0);
    if (SOCK_DGRAM == nw->type) return recvfrom(nw->sockfd, buf, len, 0, (SAP)&nw->addr, &nw->addrlen);
    return 0;
}

int close_nw(NetWork* nw)
{
    int ret = close(nw->sockfd);
    free(nw);
    return ret;
}
